#include <iostream>

#include "MethodTraceTest.h"
#include "MethodTraceAgent.h"
#include <cstring>
#include <string.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/syscall.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>

#include "jvmti.h"

using namespace std;

jvmtiEnv* MethodTraceAgent::m_jvmti = 0;
char* MethodTraceAgent::m_filter = 0;

MethodTraceAgent::~MethodTraceAgent() throw(AgentException){
    // 必须释放内存，防止内存泄露
    m_jvmti->Deallocate(reinterpret_cast<unsigned char*>(m_filter));
}

void MethodTraceAgent::Init(JavaVM *vm) const throw(AgentException){
    jvmtiEnv *jvmti = 0;
    jint ret = (vm)->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_0);
    if (ret != JNI_OK || jvmti == 0) {
        throw AgentException(JVMTI_ERROR_INTERNAL);
    }
    m_jvmti = jvmti;
}

void MethodTraceAgent::ParseOptions(const char* str) const throw(AgentException){
    if (str == 0)
        return;
    const size_t len = strlen(str);
    if (len == 0)
        return;

    // 必须做好内存复制工作
    jvmtiError error;
    error = m_jvmti->Allocate(len + 1,reinterpret_cast<unsigned char**>(&m_filter));
    CheckException(error);
    strcpy(m_filter, str);

    // 可以在这里进行参数解析的工作
    // ...
}

void MethodTraceAgent::AddCapability() const throw(AgentException){
    // 创建一个新的环境
    jvmtiCapabilities caps;
    memset(&caps, 0, sizeof(caps));
    caps.can_generate_method_entry_events = 1;
    caps.can_suspend = 1;


    // 设置当前环境
    jvmtiError error = m_jvmti->AddCapabilities(&caps);
    if (error == JVMTI_ERROR_NOT_AVAILABLE) {
    		printf("error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    }
    CheckException(error);

//	jvmtiCapabilities capa;
//	jvmtiError err;
//	err = m_jvmti->GetPotentialCapabilities(&capa);
//	if (err == JVMTI_ERROR_NONE) {
//		 cout << " ======调用了addCapabilities===> " << endl;
//		 err = m_jvmti->AddCapabilities(&capa);
//	}
}

void MethodTraceAgent::RegisterEvent() const throw(AgentException){
    // 创建一个新的回调函数
    jvmtiEventCallbacks callbacks;
    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.MethodEntry = &MethodTraceAgent::HandleMethodEntry;

    // 设置回调函数
    jvmtiError error;
    error = m_jvmti->SetEventCallbacks(&callbacks, static_cast<jint>(sizeof(callbacks)));
    CheckException(error);

    // 开启事件监听
    error = m_jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, 0);
    CheckException(error);
}

void JNICALL MethodTraceAgent::HandleMethodEntry(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID method)
{
    try {
        jvmtiError error;
        jclass clazz;
        char* name;
        char* signature;

        // 获得方法对应的类
        error = m_jvmti->GetMethodDeclaringClass(method, &clazz);
        CheckException(error);
        // 获得类的签名
        error = m_jvmti->GetClassSignature(clazz, &signature, 0);
        CheckException(error);
        // 获得方法名字
        error = m_jvmti->GetMethodName(method, &name, NULL, NULL);
        CheckException(error);

        // 根据参数过滤不必要的方法
        if(m_filter != 0){
            if (strcmp(m_filter, name) != 0)
                return;
        }
        cout << signature<< " =========> " << name << "(..)"<< endl;

        // 必须释放内存，避免内存泄露
        error = m_jvmti->Deallocate(reinterpret_cast<unsigned char*>(name));
        CheckException(error);
        error = m_jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
        CheckException(error);
    } catch (AgentException& e) {
        cout << "Error when enter HandleMethodEntry: " << e.what() << " [" << e.ErrCode() << "]";
    }
}

void describe(jvmtiError err) {
	jvmtiError err0;
	char *descr;
	err0 = MethodTraceAgent::m_jvmti->GetErrorName( err, &descr);
	if (err0 == JVMTI_ERROR_NONE) {
		printf(descr);
	} else {
		printf("error [%d]", err);
	}
}

JNIEXPORT void JNICALL Java_MethodTraceTest_getMonitors(JNIEnv *env, jclass jobj) {
	jint thr_count;
	jthread *thr_ptr;
	jthread curr_thread;
	jvmtiError error;

	error = MethodTraceAgent::m_jvmti->GetAllThreads(&thr_count, &thr_ptr);
	MethodTraceAgent::CheckException(error);

//	jvmtiCapabilities capa;
//	error = MethodTraceAgent::m_jvmti->GetCapabilities(&capa);
//	if (error == JVMTI_ERROR_NONE) {
//		capa.can_suspend  = 1;
//	}else{
//		printf("(GetCapabilities) Error expected: %d, got: %d\n", JVMTI_ERROR_NONE, error);
//		describe(error);
//	}

//	error = MethodTraceAgent::m_jvmti->SuspendThreadList(thr_count,thr_ptr,&error);
//	MethodTraceAgent::CheckException(error);
//	printf("(SuspendThreadList) Error expected: %d, got: %d\n", JVMTI_ERROR_NONE, error);
//	describe(error);
//	printf("\n");

	error = MethodTraceAgent::m_jvmti->GetCurrentThread(&curr_thread);
	describe(error);

	printf("========================== %p   %p  %p  %p %p \n", curr_thread,thr_ptr[0],thr_ptr[1],thr_ptr[2],thr_ptr[3]);

	error = MethodTraceAgent::m_jvmti->SuspendThread(thr_ptr[0]);
	describe(error);

	error = MethodTraceAgent::m_jvmti->SuspendThread(thr_ptr[1]);
	describe(error);

	error = MethodTraceAgent::m_jvmti->SuspendThread(thr_ptr[2]);
	describe(error);

	error = MethodTraceAgent::m_jvmti->SuspendThread(thr_ptr[3]);
	describe(error);

//	for(int i = 0;i<thr_count;i++) {
//		printf("========================== %p:%p ", &curr_thread,&(thr_ptr[i]));
//        if(&curr_thread != &(thr_ptr[i])){
//        	error = MethodTraceAgent::m_jvmti->SuspendThread(thr_ptr[i]);
//        	describe(error);
//        }
////		jint xx;
////		jobject* yy;
////		MethodTraceAgent::m_jvmti->GetOwnedMonitorInfo(thr_ptr[i],&xx,&yy);
////
////		printf("Number of Monitors Owned by this thread : %d\n", xx);
////		printf("========================== %p: ", yy);
//	}

	printf("==========================pid %d: ", thr_count);
}



